/*
 * 
 * Copyright 2010 David H Pollack
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * 
 */

package com.dhpollack.rotogss.servlets;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheManager;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.dhpollack.rotogss.data.RotoGSSLeagueXml;
import com.dhpollack.rotogss.data.YahooGames;
import com.dhpollack.rotogss.data.YahooGamesStats;
import com.dhpollack.rotogss.data.YahooLeagues;
import com.dhpollack.rotogss.helper.PMF;
import com.dhpollack.rotogss.helper.XPATH;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

/**
 * @author davidpl
 *
 */
public class YStoreGameStatsServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -9742696955483825L;

	private String league;
	
	private Integer game;
	
	private static XPath xPath = XPATH.get().newXPath();
	
	protected void service(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
		
		league = req.getParameter("league");
		
		if(league == null) {
			log("No league set");
			return;
		} else {
			log("Processing stats for " + league);
		}
		
		String league_include = req.getParameter("includeleague");
		Boolean addToLeague = false;
		
		if(league_include != null) {
			addToLeague = true;
			log("Adding stat keys to appropriate YahooLeague entity");
		}

		// Processing for game key.  Will be replaced with game parse
		String regex = "\\.";
		Pattern numSplit = Pattern.compile(regex);
		String[] m = numSplit.split(league);
		game = Integer.parseInt(m[0]);
		
		RotoGSSLeagueXml xml = getLeagueXmlFromApp();
		
		//Date league_update = xml.getUpdateTimestamp();
		String league_xml = xml.getLeagueXml();
		
		NodeList stat_nodes = parseLeagueXml(league_xml, "//settings/stat_categories/stats/stat");
		int stat_count = stat_nodes.getLength();
		Map<String, XPathExpression> xpath_exps = new HashMap<String, XPathExpression>();
		try {
			xpath_exps.put("stat_id", xPath.compile("stat_id"));
			xpath_exps.put("enabled", xPath.compile("enabled"));
			xpath_exps.put("name", xPath.compile("name"));
			xpath_exps.put("display_name", xPath.compile("display_name"));
			xpath_exps.put("position_type", xPath.compile("position_type"));
			//xpath_exps.put("is_only_display_stat", xPath.compile("is_only_display_stat"));
			List<Key> stat_keys = new ArrayList<Key>();
			for(int i=0;i < stat_count; i++) {
				stat_keys.add(saveGameStatsToDatastore(stat_nodes.item(i), xpath_exps));
			}
			if(addToLeague) {
				saveKeyToLeague(stat_keys);
			}
		} catch (XPathExpressionException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private NodeList parseLeagueXml(String leagues_xml, String expression) {
		NodeList n = null;
		try {
			InputSource is = new InputSource(new StringReader(leagues_xml));
			Document response = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
			n = (NodeList)xPath.evaluate( expression , response, XPathConstants.NODESET);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		return n;
	}
	

	private RotoGSSLeagueXml getLeagueXmlFromApp() {
		// TODO Auto-generated method stub
		
        Cache cache = null;

        try {
            cache = CacheManager.getInstance().getCacheFactory().createCache(Collections.emptyMap());
        } catch (CacheException e) {
            // ...
        	log("Memcache creation failed");
        }
        
        String memcache_key = league + "-xml";
        RotoGSSLeagueXml xml = null;
        
        if(cache != null && cache.containsKey(memcache_key)) {
        	log("Using Memcache");
        	xml = (RotoGSSLeagueXml) cache.get(memcache_key);
        }
        if(xml == null) {
        	log("Using Datastore");
            PersistenceManager pm = PMF.get().getPersistenceManager();
            Key key = new KeyFactory.Builder(RotoGSSLeagueXml.class.getSimpleName(), league).getKey();
            try {
            	xml = pm.getObjectById(RotoGSSLeagueXml.class, key);
            } catch(JDOObjectNotFoundException e) {
            	log("LeagueXml not found in datastore");
            	e.printStackTrace();
            }
        }
		return xml;
	}
	
	private Key saveGameStatsToDatastore(Node stat_node,
			Map<String, XPathExpression> xpath_exps)
	throws NumberFormatException, XPathExpressionException {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		XPathExpression stat_id_xpath = xpath_exps.get("stat_id");
		
		Integer stat_id = Integer.parseInt((String) stat_id_xpath.evaluate(stat_node, XPathConstants.STRING));
		//Integer stat_enabled = Integer.parseInt((String)xpath_exps.get("enabled").evaluate(stat_node, XPathConstants.STRING));
		String stat_name = (String)xpath_exps.get("name").evaluate(stat_node, XPathConstants.STRING);
		String stat_display_name = (String)xpath_exps.get("display_name").evaluate(stat_node, XPathConstants.STRING);
		String stat_position_type = (String)xpath_exps.get("position_type").evaluate(stat_node, XPathConstants.STRING);
		String stat_key = game + "-" + stat_id;
		YahooGamesStats s;
		Key key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), game)
		 .addChild(YahooGamesStats.class.getSimpleName(), stat_key)
		 .getKey();
		try {
			s = pm.getObjectById(YahooGamesStats.class, key);
			log("Found YahooGamesStat already");
		} catch(JDOObjectNotFoundException e) {
			log("YahooGamesStat not found and being created");
			// Create new StatCategory
			s = new YahooGamesStats();
	        //Set key after calling function
			s.setStatsKey(key);
	        s.setStatId(stat_id);
	        s.setStatName(stat_name);
	        s.setStatDisplayName(stat_display_name);
	        s.setStatType("stat_type");
	        s.setPositionType(stat_position_type);
	        s.setStatDivisorType("divisor");
	        s.setStatDivisorNum(1);
			try {
				pm.makePersistent(s);
			} finally {
				pm.close();
			}
		}
		if(!pm.isClosed()) {
			pm.close();
		}
		
		return key;
	}
	
	private void saveKeyToLeague(List<Key> stat_keys) {
		// TODO Auto-generated method stub
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		YahooLeagues l;
		try {
			tx.begin();
			try {
				Key key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), game)
										.addChild(YahooLeagues.class.getSimpleName(), league)
										.getKey();
				l = pm.getObjectById(YahooLeagues.class, key);
				l.setLeagueStats(stat_keys);
				pm.makePersistent(l);
			} catch(JDOObjectNotFoundException e) {
				log("YahooLeague not found to add stat key");
			}
			tx.commit();
		} finally {
			if(tx.isActive()) {
				tx.rollback();
			}
		}
		
	}

}
